
# Copyright (c) 2011
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sub license,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
# Author: Jesus Carrero <j.o.carrero@gmail.com>
# Mountain View, CA
#

""" Linear complementary problem. """

import numpy as np

class LCSolverBase(object):
    """ base class to solve the linear complementary problem. """

    __slots__ = ['m_M', 'm_b', 'm_xp', 'm_lcp_stype', 'm_constraint',
                 'm_mat_attr', 'm_sysmat', 'm_solu']

    def __init__(self, sys_eqn, load, method=None, constraint=None):
        """ Instantate an object of type LCSolverBase. """

        self.m_lcp_stype = method

        (self.m_xn, self.m_load) = (None, None)
        (self.m_tol, self.m_mat_attr) = (1.0e-03, 0)
        (self.m_constraint, self.m_mat_attr) = (None, None)
        (self.m_sysmat, self.m_solu) = (None, None)

        self.__setup(sys_eqn, load, constraint)

        if constraint == None and method == 'pSor':
            self.m_constraint = np.zeros(load.shape)

    def set_mat_attrib(self, struct):
        """ supported modes are pentadiagonal and tridiagonal. """

        if 'Penta' == struct:
            self.m_mat_attr = 5

        if 'Tridia' == struct:
            self.m_mat_attr = 3

    def get_matrix_attr(self):
        """ non-structure, pentadiagonal, triadiagonal. """

        return self.m_mat_attr

    def set_tolerance(self, tol):
        """ SSOR tolerance. """

        self.m_tol = tol

    def get_tolerance(self):
        """ tolerance use by iterative solver. """

        return self.m_tol

    def __setup(self, sys_eqn, load, constraint=None):
        """ after stiff matrix is created we need to initialize
            system constraint and make space to keep track of
            solutions iterations. """

        try:
            self.m_sysmat = sys_eqn.todense()
        except:
            self.m_sysmat = sys_eqn

        self.m_load = load
        self.m_constraint = constraint
        self.m_solu = np.zeros(load.shape)

    def get_constraint(self):
        """ vector or None ( no constraint imposed ) """

        return self.m_constraint

    def get_matrix(self):
        """ system of equations to solve. """

        return self.m_sysmat

    def get_lcp_solver_type(self):
        """ linear complementary problem solver to use.  """
        return self.m_lcp_stype

    def set_rhs(self, load):
        """ set load vector. """

        self.m_load = load

    def get_rhs(self):
        """ get load, also called rhs. """

        return self.m_load

    def solution(self):
        """ returns last solution computed. """

        return self.m_solu

